package com.yl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.profile.DefaultProfile;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yl.utils.R;
import com.yl.utils.RedisUtil;
import com.yl.vo.UserLoginVo;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yl.dao.UserDao;
import com.yl.entity.UserEntity;
import com.yl.service.UserService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.util.*;


@Service
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Resource
    private RedisUtil redisUtil;

    @Value("${aliyun.sms.signName}")
    private String signName; // 阿里云短信签名

    @Value("${aliyun.sms.templateCode}")
    private String templateCode; // 阿里云短信模板代码

    @Value("${aliyun.accessKeyId}")
    private String accessKeyId; // 阿里云Access Key ID

    @Value("${aliyun.accessKeySecret}")
    private String accessKeySecret; // 阿里云Access Key Secret

    @Override
    public UserEntity findUserByUserName(String username) {
        if (!StrUtil.isEmpty(username)) {
            LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserEntity::getUsername, username);
            UserEntity userEntity = this.getOne(wrapper);
            if (userEntity != null) {
                redisUtil.set("user" + userEntity.getId(), userEntity);
            }
            return userEntity;
        }
        return null;
    }

    @Override
    public UserEntity findUserByPhone(String username) {
        if (!StrUtil.isEmpty(username)) {
            LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserEntity::getPhone, username);
            UserEntity userEntity = this.getOne(wrapper);
            if (userEntity != null) {
                redisUtil.set("user" + userEntity.getId(), userEntity);
            }
            return userEntity;
        }
        return null;
    }

    @Override
    public R getAppLogin(UserEntity user) {
        if(!StrUtil.isEmpty(user.getPhone()) && !StrUtil.isEmpty(user.getPassword())){
            /**
             * 查询数据库是否存在该手机号的用户
             */
            LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserEntity::getPhone,user.getPhone());
            UserEntity one = this.getOne(wrapper);
            if(one.getIsDelete() == 1){
                return R.error("账号已被禁用!");
            }
            if(one != null){
                LambdaQueryWrapper<UserEntity> wrapper1 = new LambdaQueryWrapper<>();
                wrapper1.eq(UserEntity::getPhone,user.getPhone());
                BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
                boolean matches = bCryptPasswordEncoder.matches(user.getPassword(), one.getPassword());
                if(matches){
                    UserLoginVo userLoginVo = new UserLoginVo();
                    BeanUtil.copyProperties(one, userLoginVo);
                    /**
                     * 数据放入到redis中  30分钟过期
                     */
                    redisUtil.set(user.getUsername()+"_"+user.getId(),userLoginVo,18000);
                    return R.ok("登录成功!").put("data", userLoginVo);
                }
            }
            return R.error("手机号密码错误!");
        }
        return R.error("手机号或密码不能为空!");
    }

    /**
     * 用户名
     * 手机号码
     * 密码
     * 邀请码
     *
     * @param user
     * @return
     */
    @Override
    @Transactional
    public R register(UserEntity user) {
        boolean phone = mobileNumberValidator(user.getPhone());
        if (!phone) {
            return R.error("手机号码格式错误!");
        }else {
            boolean flag = redisUtil.hasKey(user.getPhone() + "_code");
            if(!flag){
                return R.error("手机号验证码错误!");
            }else {
                String phoneCode =  redisUtil.get(user.getPhone() + "_code").toString();
                if(!user.getVerificationCode().equals(phoneCode)){
                    return R.error("手机号验证码错误!");
                }
            }
        }
        if (!StrUtil.isEmpty(user.getPhone())) {
            LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper();
            wrapper.eq(UserEntity::getPhone, user.getPhone());
            UserEntity one = this.getOne(wrapper);
            if (one != null) {
                return R.error("该手机号已注册过用户!");
            }
        }
        if (!user.getSuperiorCode().equals("888888")) {
            LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper();
            wrapper.eq(UserEntity::getMyCode, user.getSuperiorCode());
            UserEntity one = this.getOne(wrapper);
            if (one == null) {
                return R.error("邀请码不存在!");
            }
        }
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode(user.getPassword());
        user.setPassword(encode);
        user.setUsername(user.getPhone() + "_" + myCode());
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setIntegralCount(new BigDecimal(0));
        if (!user.getSuperiorCode().equals("888888")) {
            LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserEntity::getSuperiorCode, user.getSuperiorId());
            UserEntity userEntity = this.getOne(wrapper);
            if (userEntity != null) {
                user.setSuperiorId(user.getId());
            }
            user.setSuperiorCode(user.getSuperiorCode());
            user.setIsDelete(0);
        } else {
            user.setSuperiorId(-1L);
        }
        user.setIsAdmin(0);
        user.setMyCode(myCode());
        user.setIsDelete(0);
        boolean flag = this.save(user);
        if (flag) {
            return R.ok("注册用户成功!");
        }
        return R.error("注册用户失败!");
    }


    public static String[] chars = new String[]{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};

    /**
     * 生成邀请码
     *
     * @return
     */
    public String myCode() {
        StringBuffer shortBuffer = new StringBuffer();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        for (int i = 0; i < 8; i++) {
            String str = uuid.substring(i * 4, i * 4 + 4);
            int x = Integer.parseInt(str, 16);
            shortBuffer.append(chars[x % 0x3E]);
        }
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserEntity::getMyCode,shortBuffer.toString());
        UserEntity one = this.getOne(wrapper);
        if(one != null){
            myCode();
        }
        return shortBuffer.toString();
    }

    @Override
    public R getSMSCode(String phone) {
        /**
         * 判断验证码是否存在、存在就删除
         */
        if(redisUtil.hasKey(phone+"_code")){
            redisUtil.del(phone+"_code");
        }
        boolean flag = mobileNumberValidator(phone);
        if (flag) {
            //验证手机号是否正确
            Random random = new Random();
            int number = 10000 + random.nextInt(90000); // 生成一个10000到99999之间的随机数
            redisUtil.set(phone+"_code", number, 300);
            return R.ok("获取验证码成功!有效时间5分钟").put("data", number);
        }
        return R.error("手机号码格式错误!");
    }

    /**
     * 获取短信验证码
     *
     * @param phone
     * @return
     */
//    @Override
//    public R getSMSCode(String phone){
//        /**
//         * 判断验证码是否存在、存在就删除
//         */
//        if(redisUtil.hasKey(phone+"_code")){
//            redisUtil.del(phone+"_code");
//        }
//        boolean flag = mobileNumberValidator(phone);
//        if (flag) {
//            boolean send = send(phone);
//            if(send){
//                return R.ok("验证码发送成功!5分钟内有效!");
//            }
//            return R.error("验证码发送失败!");
//        }
//        return R.error("手机号码格式错误!");
//    }

    /**
     * 发送短信
     *
     * @param mobile 手机号码
     * @return 是否发送成功
     */
    public boolean send(String mobile){
        Random random = new Random();
        int number = 10000 + random.nextInt(90000); // 生成一个10000到99999之间的随机数
        redisUtil.set(mobile+"_code", number, 300);
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
        IAcsClient client = new DefaultAcsClient(profile);

        SendSmsRequest request = new SendSmsRequest();
        request.setPhoneNumbers(mobile);
        request.setSignName(signName);
        request.setTemplateCode(templateCode);
        request.setTemplateParam("{\"code\":\"" + number + "\"}");

        try {
            SendSmsResponse response = client.getAcsResponse(request);
            if ("OK".equalsIgnoreCase(response.getCode())) {
                return true;
            }
        } catch (ClientException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 手机号校验
     *
     * @return
     */
    // 中国大陆手机号码正则表达式
    private static final String CHINA_MOBILE_NUMBER_REGEX = "^1[3-9]\\d{9}$";

    public boolean mobileNumberValidator(String phone) {
        if (StringUtils.isEmpty(phone)) {
            return false;
        }
        return phone.matches(CHINA_MOBILE_NUMBER_REGEX);
    }
}